package com.shanshui.customplugin;

import org.gradle.api.Plugin;
import org.gradle.api.Project
import pink.madis.apk.arsc.Chunk
import pink.madis.apk.arsc.ResourceFile
import pink.madis.apk.arsc.ResourceTableChunk
import pink.madis.apk.arsc.StringPoolChunk

import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream;

class CustomPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        println("CustomPlugin")
        project.afterEvaluate {
            boolean isProcessResourcesTask = false
            //1. 找到 ProcessXXXResources 这个task
            def processResSet = project.tasks.findAll {
                project.android.applicationVariants.all {
                    variant ->
                        if (it.name == 'process' + variant.getName() + 'Resources') {
                            isProcessResourcesTask = true
                        }
                }
                return isProcessResourcesTask
            }
            if (!isProcessResourcesTask) {
                return
            }
            //2. 将我们的自定义脚本放在 ProcessAndroidResources 这个task之后执行
            for (def processRes in processResSet) {
                processRes.doLast {
                    File[] fileList = getResPackageOutputFolder().listFiles()
                    for (def i = 0; i < fileList.length; i++) {
                        //3. 找到 .ap_ 文件
                        if (fileList[i].isFile() && fileList[i].path.endsWith(".ap_")) {
                            File packageOutputFile = fileList[i]
                            //4. 解压 .ap_ 文件
                            int prefixIndex = packageOutputFile.path.lastIndexOf(".")
                            String unzipPath = packageOutputFile.path.substring(0, prefixIndex) + File.separator
                            unZip(packageOutputFile, unzipPath)
                            //5. 解析  resources.arsc 文件，并进行图片去重操作
//                            imageOptimize(unzipPath)
                            //6. 将 解压后的文件重新打包成 .ap_ zip压缩包
                            zipFolder(unzipPath, packageOutputFile.path)

                        }
                    }

                }
            }
        }
    }

    void imageOptimize(String resourcePath) {
        // 1. 遍历 res 目录下的图片，根据 md5 寻找重复图片，并记录在 map 中，map的key为 md5，value为图片数据，文件遍历和md5计算比较简单，就不贴代码了。
        HashMap<String, ArrayList<DuplicatedEntry>> duplicatedResources = findDuplicatedResources(resourcePath);
        File arscFile = new File(resourcePath + 'resources.arsc')

        if (arscFile.exists()) {
            FileInputStream arscStream = null;

            //ResourceFile是 android-chunk-utils里面定义的数据结构
            ResourceFile resourceFile = null;
            try {
                arscStream = new FileInputStream(arscFile);

                resourceFile = ResourceFile.fromInputStream(arscStream);
                //1. 调用ResourceFile的getChunks方法，就能将arsc流转换成Chunk对象树
                List<Chunk> chunks = resourceFile.getChunks();

                HashMap<String, String> toBeReplacedResourceMap = new HashMap<String, String>(1024);

                Iterator<Map.Entry<String, ArrayList<DuplicatedEntry>>> iterator = duplicatedResources.entrySet().iterator();
                //2. 遍历 duplicatedResources 中记录的重复图片，其实这一步也可以在 findDuplicatedResources 的时候就做了
                while (iterator.hasNext()) {
                    Map.Entry<String, ArrayList<DuplicatedEntry>> duplicatedEntry = iterator.next();
                    // 保留第一个资源，索引从1开始，其他资源删除掉
                    for (def index = 1; index < duplicatedEntry.value.size(); ++index) {
                        // 删除图片，并将删除的图片信息保存在 toBeReplacedResourceMap 这个数据结构中
                        removeZipEntry(apFile, duplicatedEntry.value.get(index).name);
                        toBeReplacedResourceMap.put(duplicatedEntry.value.get(index).name, duplicatedEntry.value.get(0).name);
                    }
                }

                //3. 更新 resources.arsc 中的数据
                for (def index = 0; index < chunks.size(); ++index) {
                    Chunk chunk = chunks.get(index);
                    if (chunk instanceof ResourceTableChunk) {
                        ResourceTableChunk resourceTableChunk = (ResourceTableChunk) chunk;
                        //3. 找到字符串常量池,也是直接调用getStringPool方法即可，StringPoolChunk 也是android-chunk-utils工具中定义好的数据结构，直接使用就行
                        StringPoolChunk stringPoolChunk = resourceTableChunk.getStringPool();
                        for (def i = 0; i < stringPoolChunk.stringCount; ++i) {
                            //遍历字符串常量池的值，如果值和toBeReplacedResourceMap中包含的值相等，则进行替换
                            def key = stringPoolChunk.getString(i);
                            if (toBeReplacedResourceMap.containsKey(key)) {
                                stringPoolChunk.setString(i, toBeReplacedResourceMap.get(key));
                            }
                        }
                    }
                }
            } catch (IOException ignore) {
            } catch (FileNotFoundException ignore) {
            } finally {
                if (arscStream != null) {
                    IOUtils.closeQuietly(arscStream);
                }
            }
        }

    }

// 文件的解压和压缩实现如下
    def unZip(File src, String savepath) throws IOException {
        def count = -1;
        def index = -1;
        def flag = false;
        def file1 = null;
        def is = null;
        def fos = null;
        def bos = null;

        ZipFile zipFile = new ZipFile(src);
        Enumeration<?> entries = zipFile.entries();

        while (entries.hasMoreElements()) {
            def buf = new byte[2048];
            ZipEntry entry = (ZipEntry) entries.nextElement();
            def filename = entry.getName();

            filename = savepath + filename;
            File file2 = file(filename.substring(0, filename.lastIndexOf('/')));

            if (!file2.exists()) {
                file2.mkdirs()
            }

            if (!filename.endsWith("/")) {

                file1 = file(filename);
                file1.createNewFile();
                is = zipFile.getInputStream(entry);
                fos = new FileOutputStream(file1);
                bos = new BufferedOutputStream(fos, 2048);

                while ((count = is.read(buf)) > -1) {
                    bos.write(buf, 0, count);
                }

                bos.flush();

                fos.close();
                is.close();

            }
        }

        zipFile.close();

    }

    def zipFolder(String srcPath, String savePath) throws IOException {
        def saveFile = file(savePath)
        saveFile.delete()
        saveFile.createNewFile()
        def outStream = new ZipOutputStream(new FileOutputStream(saveFile))
        def srcFile = file(srcPath)
        zipFile(srcFile.getAbsolutePath() + File.separator, "", outStream)
        outStream.finish()
        outStream.close()
    }

    def zipFile(String folderPath, String fileString, ZipOutputStream out) throws IOException {
        File srcFile = file(folderPath + fileString)
        if (srcFile.isFile()) {
            def zipEntry = new ZipEntry(fileString)
            def inputStream = new FileInputStream(srcFile)
            out.putNextEntry(zipEntry)
            def len
            def buf = new byte[2048]
            while ((len = inputStream.read(buf)) != -1) {
                out.write(buf, 0, len)
            }
            out.closeEntry()
        } else {
            def fileList = srcFile.list()
            if (fileList.length <= 0) {
                def zipEntry = new ZipEntry(fileString + File.separator)
                out.putNextEntry(zipEntry)
                out.closeEntry()
            }

            for (def i = 0; i < fileList.length; i++) {
                zipFile(folderPath, fileString.equals("") ? fileList[i] : fileString + File.separator + fileList[i], out)
            }
        }
    }
}